/**
 * Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * ---------------------------------------------------------------------------
 * 
 * Flex definition file for syntax highlighting.
 * 
 */

package karel.lang.syntaxhighlight;

import java.util.EmptyStackException;
import java.util.Stack;
import jsyntaxpane.Token;
import jsyntaxpane.TokenType;
import jsyntaxpane.lexers.DefaultJFlexLexer;

%%

%public
%class KarelHighlightingLexer
%extends DefaultJFlexLexer
%final
%unicode
%char
%type Token

%{
    private Stack<Boolean> funOrNot;

    public KarelHighlightingLexer() {
        super();
        funOrNot = new Stack<Boolean>();
    }

    @Override
    public int yychar() {
        return yychar;
    }

    private String[] keywords = {"stef","breyta","ef","annars","annars ef","meðan","skila","endurtaka","satt","ósatt"};
    private String add = "(\\s*)[(]";
    
    private boolean isKeyWord(String str) {
        for(int i =0; i < keywords.length; i++) {
            if(str.matches(keywords[i]+add)) {
                return true;
            }
        }
        return false;
    }
    
    private boolean isTrue(String str) {
        return str.matches("satt"+add);
    }

    private boolean isFalse(String str) {
        return str.matches("ósatt"+add);
    }
%}

/* ---------- START Syntax highlighting sync ---------- */

NL  = \n | \r | \r\n
WHITESPACE = [ \t]+

COMMENT = "##" [^\r\n]*

MLCOMMENTSTART = "#{"
MLCOMMENTSTOP = "}#"

NAME = [:jletter:] [:jletterdigit:]*
FUNC = {NAME}(WHITESPACE | " ")*"("

DIGIT = [0-9]+
INT = {DIGIT}
DOUBLE = {DIGIT} ("." {DIGIT})? (("e"|"E")("+"|"-")?{DIGIT})?
STRING = (\" ( [^\"\n\\] | \\[^\n] )* (\n | \\\n | \"))

%state VAROFFUNC
%state MLCOMMENT

%%

<YYINITIAL> {

/* keywords */
    "stef"      { return token(TokenType.KEYWORD); }
    "breyta"    { return token(TokenType.KEYWORD); }
    "ef"        { return token(TokenType.KEYWORD); }
    "annars"    { return token(TokenType.KEYWORD); }
    "annars ef" { return token(TokenType.KEYWORD); }
    "me\u00F0an"     { return token(TokenType.KEYWORD); }
    "skila"     { return token(TokenType.KEYWORD); }
    "endurtaka" { return token(TokenType.KEYWORD); }
    "satt"      { return token(TokenType.TYPE2); }
    "\u00F3satt"     { return token(TokenType.TYPE3); }

/* program operators */
    "=" |
    "," |
    "{" |
    "}" |   
    "+" | 
    "-" | 
    "*" | 
    "/" | 
    "^" |
    ">" |
    "<" |
    ">="|
    "<="|
    "=="|
    "!="|
    "||"|
    "&&"|
    "og"|
    "e\u00F0a"|
    "!" |
    "ekki"   { return token(TokenType.OPERATOR); }

    "("      { funOrNot.push(false); return token(TokenType.OPERATOR); }
    ")"      { try { if(funOrNot.pop()) {return token(TokenType.COMMENT2);} return token(TokenType.OPERATOR); } catch (EmptyStackException e) { return token(TokenType.OPERATOR); } }

/* FUNC */
    {FUNC}  { 
            if(isKeyWord(yytext())) {
                TokenType rettoken = TokenType.KEYWORD;
                if(isTrue(yytext())) {
                    rettoken = TokenType.TYPE2;
                } else if (isFalse(yytext())) {
                    rettoken = TokenType.TYPE3;
                }
                funOrNot.push(false);
                yypushback(1);
                return token(rettoken);
            } else {
                funOrNot.push(true); return token(TokenType.COMMENT2); 
            }
            }


/* VAR   */
    {NAME}   { return token(TokenType.IDENTIFIER); }    

/* numbers */
    {INT}    { return token(TokenType.NUMBER); }
            
    {DOUBLE} { return token(TokenType.NUMBER); }

    {STRING} { return token(TokenType.STRING); }

/* other */
    {MLCOMMENTSTART} { yybegin(MLCOMMENT); return token(TokenType.COMMENT);}
    {WHITESPACE}    { }
    {COMMENT}       { return token(TokenType.COMMENT); }
}

<MLCOMMENT> {
    {MLCOMMENTSTOP} {   yybegin(YYINITIAL); return token(TokenType.COMMENT); }
    . | {NL}        {   return token(TokenType.COMMENT);}
}

<VAROFFUNC> {
    "("             { }
    ")"             { yybegin(YYINITIAL); return token(TokenType.COMMENT2); }
    . | {NL}        { /* skip */ }
}
/* Comment2 */
/* ---------- STOP Syntax highlighting sync ---------- */

/* do not change */
<YYINITIAL> . | {NL}    { /* skip */ }
<YYINITIAL> <<EOF>>     { return null; }